package cn.ittgh.controller.User;

import cn.hutool.core.util.StrUtil;
import cn.ittgh.pojo.Commons.PageBean;
import cn.ittgh.pojo.Commons.Result;
import cn.ittgh.pojo.User.User;
import cn.ittgh.service.User.UserService;
import cn.ittgh.utils.EnumsUtil;
import cn.ittgh.utils.JwtUtil;
import cn.ittgh.utils.MD5Util;
import cn.ittgh.utils.ThreadLocalUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.constraints.Pattern;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/user")
@Validated
public class UserController {


    @Value("${md5.salt}")
    private String salt;

    @Value("${verifyCode.type}")
    private String codeType;

    @Value("${spring.data.redis.tokenMaxTimes}")
    private int tokenMaxTimes;

    @Autowired
    private UserService userService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @PostMapping("/register")
    public <T> Result<T> register(
            HttpServletRequest request,
            @Pattern(regexp = "^\\S{1,16}$") String userName,
            @Pattern(regexp = "^\\S{5,16}$") String password,
            EnumsUtil.Roles roles) {

        EnumsUtil.PlatformType platformType = EnumsUtil.PlatformType.valueOf(request.getHeader("platformType"));
        User user = new User(userName, password, roles, platformType);
        // checkout user
        User dbUser = userService.findByUserNameAndPlatformType(user.getUserName(), user.getPlatformType());
        // register user
        if (dbUser == null) {
            Boolean status = userService.register(user);
            if (status) {
                return Result.success();
            } else {
                return Result.error("注册失败");
            }

        }
        // userName already exists
        return Result.error("用户名已存在");
    }

    @PostMapping("/login")
    public <T> Result<T> login(
            HttpServletRequest request,
            String userName,
            String password,
            String phoneNumber,
            String codeId,
            String codeValue
    ) {
        EnumsUtil.PlatformType platformType = EnumsUtil.PlatformType.valueOf(request.getHeader("platformType"));
        User user; // 登录用户
        User dbUser; // 数据库用户
        String token; // token
        ValueOperations<String, String> redisOperations = stringRedisTemplate.opsForValue(); // redis
        //web平台
        if (platformType == EnumsUtil.PlatformType.WEB) {
            // 验证 codeType 验证码
            String redisLoginKey = "user:login:" + codeType + ":" + codeId;

            String redisLoginCode = redisOperations.get(redisLoginKey); // 根据获取的redis的key 查询redis里面存储的验证码

            // 比较输入的和redis存储验证码是否一致
            if (StrUtil.isEmpty(redisLoginCode) || !StrUtil.equalsIgnoreCase(redisLoginCode, codeValue)) {
                return Result.error("验证码错误");
            }
            // 登录
            user = new User(userName, password, platformType);

            dbUser = userService.findByUserNameAndPlatformType(user.getUserName(), user.getPlatformType());
            if (dbUser != null) {
                // 帐号、密码判断
                if (!user.getUserName().equals(dbUser.getUserName()) || !MD5Util.verifyMD5(user.getPassword(), dbUser.getPassword(), salt)) {
                    return Result.error("帐号密码不正确！");
                }
                // 登录
                token = getUserTokenAndLogin(dbUser);

                // redis 缓存token
                redisOperations.set("user:token:" + token, token, tokenMaxTimes, TimeUnit.HOURS);

                // 删除redis里面验证码
                stringRedisTemplate.delete(redisLoginKey);

                Map<String, Object> map = new HashMap<>();

                map.put("token", token);
                map.put("userId", dbUser.getId());
                return (Result<T>) Result.success(map);
            }
            return Result.error("用户不存在");
        } else if (platformType == EnumsUtil.PlatformType.MINIAPP) {
            // 微信小程序
            user = new User(userName, phoneNumber, platformType, EnumsUtil.Roles.GENERAL_USER);
            dbUser = userService.findByPhoneNumber(user.getPhoneNumber());
            if (dbUser == null) {
                // 注册
                Boolean status = userService.register(user);
                dbUser = userService.findByPhoneNumber(user.getPhoneNumber());
                if (!status) {
                    return Result.error("注册失败");
                }
            }
            // 登录
            assert dbUser != null;
            Map<String, Object> map = new HashMap<>();

            token = getUserTokenAndLogin(dbUser);

            // redis 缓存token
            redisOperations.set("user:token:" + token, token, tokenMaxTimes, TimeUnit.HOURS);

            map.put("token", token);
            map.put("userId", dbUser.getId());
            return (Result<T>) Result.success(map);

        }
        return Result.error("暂不支持当前平台登录!");
    }

    @GetMapping("/logout")
    public Result logout(HttpServletRequest request) {
        String userId = ThreadLocalUtil.getUserId();
        User dbUser = userService.findByUserId(userId);
        if (dbUser == null) {
            return Result.error("登出失败,当前用户不存在");
        }
        // update user login status
        userService.logout(dbUser);

        // 删除redis 中的token
        stringRedisTemplate.delete("user:token:" + request.getHeader("Authorization"));

        return Result.success("登出成功");
    }

    @GetMapping("/userInfo")
    public Result<User> getUserInfo() {
        User user = userService.findByUserId(ThreadLocalUtil.getUserId());
        return Result.success(user);
    }

    @PostMapping("/update")
    public <T> Result<T> updateUserInfo(@RequestBody @Validated User user) {
        user.setId(ThreadLocalUtil.getUserId());
        user.setUpdateTime(LocalDateTime.now());
        Boolean status = userService.updata(user);
        if (status) {
            return Result.success();
        } else {
            return Result.error("更新失败!");
        }
    }

    @GetMapping("/list")
    public Result<PageBean<User>> userList(
            Integer pageNum,
            Integer pageSize,
            @RequestParam(required = false) EnumsUtil.UserStatus status,
            @RequestParam(required = false) EnumsUtil.Roles roles,
            @RequestParam(required = false) EnumsUtil.PlatformType platformType
    ) {
        PageBean<User> userList = userService.list(pageNum, pageSize, roles, status, platformType);
        return Result.success(userList);

    }

    public String getUserTokenAndLogin(User user) {
        // 获取token
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", user.getId());
        claims.put("userName", user.getUserName());
        String token = JwtUtil.getToken(claims);

        // 更新登录状态
        User updateUser = new User();
        updateUser.setId(user.getId());
        userService.updata(updateUser);
        return token;
    }
}
